package org.footito.android.data.update;

import java.io.BufferedInputStream;
import java.io.StringReader;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.GregorianCalendar;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.util.ByteArrayBuffer;
import org.footito.android.api.CommentFromAPI;
import org.footito.android.api.CommentsApiHandler;
import org.footito.android.api.GroupsTeamApiHandler;
import org.footito.android.api.GroupsTeamFromAPI;
import org.footito.android.api.RefreshParams;
import org.footito.android.api.StatusApiHandler;
import org.footito.android.api.StatusFromAPI;
import org.footito.android.api.TeamApiHandler;
import org.footito.android.api.TeamFromAPI;
import org.footito.android.connexion.FootitoConnexion;
import org.footito.android.data.database.FootitoDatabaseAdapter;
import org.footito.android.data.update.UpdateTaskListener.ProgressEvents;
import org.footito.android.tools.Log;
import org.footito.android.tools.Settings;
import org.footito.android.ui.activity.Timeline;
import org.footito.android.ui.notifications.NotificationsManager;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import android.content.Context;
import android.os.AsyncTask;

public class UpdateDataTask extends AsyncTask<Void, Void, Void> {
	private FootitoConnexion connexion;
	private UpdateTaskListener listener;
	private Context context;
	private RefreshParams params;
	private boolean newStatuts = false;
	private int mStatusAdded;
	private NotificationsManager nm;

	public UpdateDataTask(Context context, UpdateTaskListener listener) {
		this.connexion = FootitoConnexion.getInstance(context);
		this.listener = listener;
		this.context = context;
		nm = new NotificationsManager(context);
	}

	public void setParams(RefreshParams params) {
		this.params = params;
	}

	private void performCompleteUpdate(RefreshParams params) {
		try {
			ArrayList<GroupsTeamFromAPI> groups = performUpdateGroupsTeam(params);
			ArrayList<TeamFromAPI> teams = performUpdateTeams(params);
			ArrayList<StatusFromAPI> status = performUpdateStatus(params);
			ArrayList<CommentFromAPI> comments = performUpdateComments(params);

			FootitoDatabaseAdapter dbAdapter = FootitoDatabaseAdapter.getInstance(context);
			dbAdapter.insertComments(comments);
			dbAdapter.insertGroupsTeam(groups);
			int statusAdded = dbAdapter.insertStatus(status);
			dbAdapter.insertTeams(teams);

			Settings.setLastCheck(context, new GregorianCalendar());
			Settings.setInitialized(context, true);

			if ((statusAdded > 0) && !Timeline.isRunning) {
				Settings.incrementTimelinePositionOf(context, statusAdded);
				newStatuts = true;
				mStatusAdded = statusAdded;
			}
			listener.onComplete(statusAdded);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private ArrayList<CommentFromAPI> performUpdateComments(RefreshParams params) throws Exception {
		if (listener != null)
			listener.onProgress(ProgressEvents.COMMENTS_START, 0);

		StringBuilder urlstring = new StringBuilder(CommentsApiHandler.URL_API + "?");

		if (params != null) {
			if (params.getPublishAfter() != null)
				urlstring.append(CommentsApiHandler.URL_API_PUBLISHED_AFTER + "=" + params.getPublishAfter() + "&");
		}

		URL url = new URL(urlstring.toString());
		Log.d(url.toString());

		String xml = downloadXML(connexion.getHttpClient(), url, listener);

		/* Get a SAXParser from the SAXPArserFactory. */
		SAXParserFactory spf = SAXParserFactory.newInstance();
		SAXParser sp = spf.newSAXParser();

		/* Get the XMLReader of the SAXParser we created. */
		XMLReader xr = sp.getXMLReader();

		/* Create a new ContentHandler and apply it to the XML-Reader */
		CommentsApiHandler commentApiHandler = new CommentsApiHandler();
		xr.setContentHandler(commentApiHandler);

		/* Parse the xml-data from our URL. */
		xr.parse(new InputSource(new StringReader(xml)));

		if (listener != null)
			listener.onProgress(ProgressEvents.COMMENTS_END, 0);

		return commentApiHandler.getCommentsFromAPIsList();
	}

	private ArrayList<StatusFromAPI> performUpdateStatus(RefreshParams params) throws Exception {
		if (listener != null)
			listener.onProgress(ProgressEvents.STATUS_START, 0);

		StringBuilder urlstring = new StringBuilder(StatusApiHandler.URL_API + "?");
		if (params != null) {

			if (params.getPublishAfter() != null)
				urlstring.append(StatusApiHandler.URL_API_PUBLISHED_AFTER + "=" + params.getPublishAfter() + "&");

			if (params.getLimit() > -1)
				urlstring.append("limit=" + params.getLimit() + "&");

			if (params.getOffset() > -1)
				urlstring.append("offset=" + params.getOffset() + "&");

			if (params.getTeamId() > -1)
				urlstring.append("team=" + params.getTeamId() + "&");

		}
		URL url = new URL(urlstring.toString());
		Log.d(url.toString());

		String xml = downloadXML(connexion.getHttpClient(), url, listener);

		/* Get a SAXParser from the SAXPArserFactory. */
		SAXParserFactory spf = SAXParserFactory.newInstance();
		SAXParser sp = spf.newSAXParser();

		/* Get the XMLReader of the SAXParser we created. */
		XMLReader xr = sp.getXMLReader();

		/* Create a new ContentHandler and apply it to the XML-Reader */
		StatusApiHandler statusApiHandler = new StatusApiHandler();
		xr.setContentHandler(statusApiHandler);

		/* Parse the xml-data from our URL. */
		xr.parse(new InputSource(new StringReader(xml)));

		if (listener != null)
			listener.onProgress(ProgressEvents.STATUS_END, 0);

		return statusApiHandler.getStatusList();

	}

	private ArrayList<TeamFromAPI> performUpdateTeams(RefreshParams params) throws Exception {
		if (listener != null)
			listener.onProgress(ProgressEvents.TEAMS_START, 0);

		StringBuilder urlstring = new StringBuilder(TeamApiHandler.URL_API + "?");

		if (params != null) {
			if (params.getPublishAfter() != null)
				urlstring.append(TeamApiHandler.URL_API_UPDATED_AFTER + "=" + params.getPublishAfter() + "&");
		}

		URL url = new URL(urlstring.toString());
		Log.d(url.toString());

		String xml = downloadXML(connexion.getHttpClient(), url, listener);

		/* Get a SAXParser from the SAXPArserFactory. */
		SAXParserFactory spf = SAXParserFactory.newInstance();
		SAXParser sp = spf.newSAXParser();

		/* Get the XMLReader of the SAXParser we created. */
		XMLReader xr = sp.getXMLReader();

		/* Create a new ContentHandler and apply it to the XML-Reader */
		TeamApiHandler teamApiHandler = new TeamApiHandler();
		xr.setContentHandler(teamApiHandler);

		/* Parse the xml-data from our URL. */
		xr.parse(new InputSource(new StringReader(xml)));

		if (listener != null)
			listener.onProgress(ProgressEvents.TEAMS_END, 0);

		return teamApiHandler.getTeamList();

	}

	private ArrayList<GroupsTeamFromAPI> performUpdateGroupsTeam(RefreshParams params) throws Exception {
		if (listener != null)
			listener.onProgress(ProgressEvents.TEAMS_START, 0);

		StringBuilder urlstring = new StringBuilder(GroupsTeamApiHandler.URL_API + "?");

		if (params != null) {
			if (params.getPublishAfter() != null)
				urlstring.append(GroupsTeamApiHandler.URL_API_UPDATED_AFTER + "=" + params.getPublishAfter() + "&");
		}

		URL url = new URL(urlstring.toString());
		Log.d(url.toString());

		String xml = downloadXML(connexion.getHttpClient(), url, listener);

		/* Get a SAXParser from the SAXPArserFactory. */
		SAXParserFactory spf = SAXParserFactory.newInstance();
		SAXParser sp = spf.newSAXParser();

		/* Get the XMLReader of the SAXParser we created. */
		XMLReader xr = sp.getXMLReader();

		/* Create a new ContentHandler and apply it to the XML-Reader */
		GroupsTeamApiHandler groupsTeamApiHandler = new GroupsTeamApiHandler();
		xr.setContentHandler(groupsTeamApiHandler);

		/* Parse the xml-data from our URL. */
		xr.parse(new InputSource(new StringReader(xml)));

		if (listener != null)
			listener.onProgress(ProgressEvents.TEAMGROUPS_END, 0);

		return groupsTeamApiHandler.getGroupsTeamList();
	}

	public static String downloadXML(HttpClient client, URL url, UpdateTaskListener listener) throws Exception {
		String res = "";
		// Utils.debugger.logInfo(TAG, "Download start");

		HttpResponse response = null;
		BufferedInputStream bis = null;

		try {
			URI uri = url.toURI();
			HttpPost request = new HttpPost(uri);

			response = client.execute(request);
			long length = response.getEntity().getContentLength();
			long tenPercent = length / 10;
			if (tenPercent < 1)
				tenPercent = 1;
			bis = new BufferedInputStream(response.getEntity().getContent());

			if (response.getStatusLine().getStatusCode() != 200)
				throw new Exception();

			int cis = 0;
			ByteArrayBuffer baf = new ByteArrayBuffer(50);
			long i = 0;
			while ((cis = bis.read()) != -1) {
				baf.append((byte) cis);
				i++;
				if (length > 0) {
					long div = (i / tenPercent) * 10;
					long modulo = i % tenPercent;
					if (modulo == 0) {
						listener.onProgress(UpdateTaskListener.ProgressEvents.DOWNLOAD, (int) div);
					}
				}
			}

			bis.close();

			res = new String(baf.toByteArray());
		} catch (Exception e) {

			if (bis != null) {
				try {
					bis.close();
				} catch (Exception e1) {
					Log.d("No important:" + e1.getClass().getName() + ": " + e1.getMessage());
				}
			}

			throw (e);
		}

		return res;
	}

	interface UpdateTaskListenerLocal extends UpdateTaskListener {
	}

	@Override
	protected void onPreExecute() {
		nm.showNotificationDownloading();
		super.onPreExecute(); 
	}

	@Override
	protected Void doInBackground(Void... params) {
		performCompleteUpdate(UpdateDataTask.this.params);
		return null;
	}

	@Override
	protected void onPostExecute(Void result) {
		if (newStatuts) {
			nm.sendNewStatus(context, mStatusAdded);
		}
		nm.removeNotificationDownloading();
		super.onPostExecute(result);
	}

}
